﻿using CalligraphyWeb;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using ThuPhap.Models;
using System.Data.Entity;
using ThuPhap.Class;
using CalligraphyWeb.Models;

namespace Calligraphy.Models
{
    public class Template
    {
        #region Data Members
        private template data;
        public template Data
        {
            get
            {
                if (data == null)
                    data = new template();

                return data;
            }
            set
            {
                if (data == value) return;
                data = value;
            }
        }
        #endregion

        #region Class Methods
        public Template()
        {
            this.data = new template();
        }

        public Template(int id, bool isLazy = true)
        {
            Get(id, isLazy);
        }

        public Template(template obj)
        {
            Get(obj);
        }

        public Template(ThuPhap.Models.Template tpl)
        {
            Get(tpl);
        }

        public Template(string name, string description, item item)
        {
            Get(name, description, item);
        }

        public Template Get(int id, bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var query = from c in db.templates
                            where c.id == id
                            select c;
                if (!isLazy) query = query.Include(o => o.templateControls);

                if (query.Count() > 0)
                {
                    var obj = query.FirstOrDefault();
                    return Get(obj);
                }
                else
                    return null;
            }
        }

        public Template Get(template obj)
        {
            if (this.data == obj) return this;

            this.data = obj;
            return this;
        }

        public Template Get(ThuPhap.Models.Template tpl)
        {
            string bgDir = HttpRuntime.AppDomainAppPath + "\\Data\\TemplateBackgrounds\\";
            string exDir = HttpRuntime.AppDomainAppPath + "\\Data\\TemplateImages\\";
            //save image files
            //background
            MemoryStream ms = new MemoryStream(tpl.Background);
            Image bgImg = Image.FromStream(ms);
            string bgFilename = "tplbg-" + Guid.NewGuid() + ".png";
            string bgFileDir = bgImg + bgFilename;
            bgImg.Save(bgFileDir, ImageFormat.Png);

            //exported image
            ms = new MemoryStream(tpl.Image);
            Image exImg = Image.FromStream(ms);
            string exFileName = "tplex-" + Guid.NewGuid() + ".png";
            string exFileDir = exDir + exFileName;
            bgImg.Save(exFileName, ImageFormat.Png);

            this.data = new template() {
                thumbnail = exFileName,
                image = bgFilename,
                name = tpl.Name,
                description = tpl.Description,
                x = 0,
                y = 0,
                width = bgImg.Width,
                height = bgImg.Height,
                status = "active",
                userid = 0
            };

            foreach (var iter in tpl.TextControl)
            {
                var temp = new templateControl()
                {
                    id = 0,
                    align = iter.Align,
                    fontFamily = iter.FontFamily,
                    fontSize = iter.FontSize,
                    foreground = iter.Foreground,
                    height = iter.Height,
                    width = iter.Width,
                    isBold = iter.IsBold,
                    isItalic = iter.IsItalic,
                    isSelected = iter.IsSelected,
                    C_left = iter.Left,
                    C_top = iter.Top,
                    text = iter.Text,
                    unicodeText = iter.UnicodeText,
                    type = iter.Type
                };

                this.data.templateControls.Add(temp);
            }

            return this;
        }

        public Template Get(string name, string description, item item)
        {
            string bgDir = HttpRuntime.AppDomainAppPath + "Data\\Backgrounds\\";
            string exDir = HttpRuntime.AppDomainAppPath + "Data\\ItemImages\\";
            string templateBackgroundDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateBackgrounds\\";
            string TemplateImageDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateImages\\";
            string galleriesDir = HttpRuntime.AppDomainAppPath + "Data\\Galleries\\";

            Image background = null;

            this.data = new template();

            //copy images
            if (File.Exists(bgDir + item.background))
                background = Image.FromFile(bgDir + item.background); //background
            else if (File.Exists(galleriesDir + item.background))
                background = Image.FromFile(galleriesDir + item.background); //background

            string backgroundPath = "";
            if (background != null)
            {
                backgroundPath = templateBackgroundDir + item.background;
                if (!File.Exists(backgroundPath))
                    background.Save(backgroundPath);
                data.image = item.background;
            }

            //Converting
            this.data.id = 0;
            this.data.name = name;
            this.data.description = description;
            this.data.height = item.height;
            this.data.userid = item.userid;
            this.data.status = "active";
            this.data.width = background.Width;
            this.data.height = background.Height;
            this.data.x = 0;
            this.data.y = 0;
            this.data.created = DateTime.Now;
            this.data.updated = DateTime.Now;

            //text controls
            foreach (var iter in item.itemControls)
            {
                TemplateControl temp = new TemplateControl(iter);
                this.data.templateControls.Add(temp.Data);
            }
            var previewFileName = ExportImage.Export(data);
            this.data.thumbnail = previewFileName;

            return this;
        }
        public item ToItem()
        {
            var item = new Item(this.data);
            return item.Data;
        }

        public Item ToItemInterface()
        {
            var item = new Item(this.data);
            return item;
        }

        public TemplateThumbnail ToThumbnail()
        {
            var result = new TemplateThumbnail() { 
                ID = this.data.id,
                Name = this.data.name,
                Date = this.data.updated.Value,
                Thumbnail = this.data.thumbnail,
                UserID = this.data.userid.HasValue ? this.data.userid.Value : 0
            };
            if (this.data.userid.HasValue)
            {
                if (this.data.userid.Value > 0)
                {
                    var user = new User(this.data.userid.Value);
                    result.Username = user.Data.username;
                }
            }

            return result;
        }

        public ThuPhap.Models.Template ToPhoneTemplate()
        {
            if (this.data == null) return null; 
            string templateBackgroundDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateBackgrounds\\";
            string TemplateImageDir = HttpRuntime.AppDomainAppPath + "Data\\TemplateImages\\";

            ImageConverter converter = new ImageConverter();
            Image background = null;
            Image preview = null;
            byte[] bgArray = null;
            byte[] previewArray = null;

            double width = 480;
            double height = 800;
            if (File.Exists(templateBackgroundDir + data.image))
            {
                background = Image.FromFile(templateBackgroundDir + data.image);
                bgArray = (byte[])converter.ConvertTo(background, typeof(byte[]));
                width = background.Width;
                height = background.Height;
            }

            if (File.Exists(TemplateImageDir + data.thumbnail))
            {
                preview = Image.FromFile(TemplateImageDir + data.thumbnail);
                previewArray = (byte[])converter.ConvertTo(preview, typeof(byte[]));

            }

            var result = new ThuPhap.Models.Template()
            {
                ID = data.id,
                Name = data.name,
                Description = data.description,
                Background = bgArray,
                BackgroundWidth = width,
                BackgroundHeight = height,
                Date = DateTime.Today,
                Image = previewArray,
                TextControl = new ObservableCollection<TextControlInfo>()
            };

            foreach (var iter in data.templateControls)
            {
                using (calligraphyEntities db = new calligraphyEntities())
                {
                    db.Configuration.LazyLoadingEnabled = false;
                    var ff = db.fontFamilies.SingleOrDefault(o => o.name == iter.fontFamily);
                    var color = ColorTranslator.FromHtml("#" + iter.foreground);
                    string foreground = color.A + "_" + color.R + "_" + color.G + "_" + color.B;
                    var temp = new TextControlInfo()
                    {
                        Align = iter.align.Value,
                        FontFamily = ff.phonePath,
                        FontSize = iter.fontSize.Value / 0.8,
                        Foreground = foreground,
                        Height = iter.height.Value,
                        IsBold = iter.isBold.Value,
                        IsItalic = iter.isItalic.Value,
                        IsSelected = iter.isSelected.Value,
                        Left = iter.C_left.Value,
                        Top = iter.C_top.Value,
                        Text = iter.text,
                        UnicodeText = iter.unicodeText,
                        Type = iter.type.Value,
                        Width = iter.width.Value

                    };

                    result.TextControl.Add(temp);
                }
            }

            return result;
        }

        private int Insert()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                this.data.created = this.data.updated = DateTime.Today;
                db.templates.Add(data);

                //add template controls
                foreach (var iter in data.templateControls)
                {
                    iter.id = data.id;
                    db.templateControls.Add(iter);
                }
                db.SaveChanges();
                return data.id;
            }
        }

        private int Update()
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var saved = db.templates.SingleOrDefault(o => o.id == this.data.id);
                
                saved.description = data.description;
                saved.height = data.height;
                saved.image = data.image;
                saved.name = data.name;
                saved.status = data.status;
                saved.thumbnail = data.thumbnail;
                saved.updated = DateTime.Today;
                saved.userid = data.userid;
                saved.width = data.width;
                saved.x = data.x;
                saved.y = data.y;

                db.templates.Attach(saved);
                db.Entry(saved).State = System.Data.EntityState.Modified;

                //add template controls
                var temps = db.templateControls.Where(o => o.templateID == data.id);
                foreach (var iter in temps)
                {
                    db.templateControls.Remove(iter);
                }

                foreach (var iter in data.templateControls)
                {
                    iter.templateID = saved.id;
                    db.templateControls.Add(iter);
                }

                db.SaveChanges();
                return data.id;
            }
        }

        public int Save()
        {
            if (data.id == 0)
                return Insert();
            else
                return Update();
        }

        public int Delete()
        {
            
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var obj = db.templates.SingleOrDefault(o => o.id == data.id);
                var controls = from c in db.templateControls
                               where c.templateID == obj.id
                               select c;

                foreach (var iter in controls)
                    db.templateControls.Remove(iter);

                db.templates.Remove(obj);
                db.SaveChanges();
                return 1;
            }
        }
        #endregion

        #region Static Methods
        public static ObservableCollection<template> Get(string sortColumn = "id", bool isAsc = false,
                                                    int pageIndex = 1, int pageSize = int.MaxValue,
                                                    bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                IQueryable<template> query = db.templates.AsQueryable();
                if (!isLazy) query = query.Include(o => o.templateControls)
                    .Include(o => o.user);

                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query == null)
                    return new ObservableCollection<template>();
                else
                    return new ObservableCollection<template>(query.ToList());
            }
        }

        public static List<long> Save(Collection<template> collection)
        {
            var result = new List<long>();
            foreach (var obj in collection)
            {
                var temp = new Template(obj);
                result.Add(temp.Save());
            }

            return result;
        }

        public static int Delete(Collection<template> collection)
        {
            int result = 0;
            using (calligraphyEntities db = new calligraphyEntities())
            {
                foreach (var obj in collection)
                {
                    foreach (var iter in obj.templateControls)
                        db.templateControls.Remove(iter);
                    db.templates.Remove(obj);
                    result++;
                }

                db.SaveChanges();
            }
            return result;
        }

        private static IQueryable<template> Sorting(IQueryable<template> query, string sortColumn = "id", bool isAsc = false)
        {
            switch (sortColumn)
            {
                case "name":
                    query = isAsc ? query.OrderBy(o => o.name) : query.OrderByDescending(o => o.name);
                    break;
                case "description":
                    query = isAsc ? query.OrderBy(o => o.description) : query.OrderByDescending(o => o.description);
                    break;
                case "thumbnail":
                    query = isAsc ? query.OrderBy(o => o.thumbnail) : query.OrderByDescending(o => o.thumbnail);
                    break;
                case "image":
                    query = isAsc ? query.OrderBy(o => o.image) : query.OrderByDescending(o => o.image);
                    break;
                case "author":
                    query = isAsc ? query.OrderBy(o => o.userid) : query.OrderByDescending(o => o.userid);
                    break;
                case "status":
                    query = isAsc ? query.OrderBy(o => o.status) : query.OrderByDescending(o => o.status);
                    break;
                case "url":
                    query = isAsc ? query.OrderBy(o => o.url) : query.OrderByDescending(o => o.url);
                    break;
                case "date":
                    query = isAsc ? query.OrderBy(o => o.updated) : query.OrderByDescending(o => o.updated);
                    break;
                case "created":
                    query = isAsc ? query.OrderBy(o => o.created) : query.OrderByDescending(o => o.created);
                    break;
                case "id":
                default:
                    query = isAsc ? query.OrderBy(o => o.id) : query.OrderByDescending(o => o.id);
                    break;
            }

            return query;
        }

        private static IQueryable<template> Paging(IQueryable<template> query, int pageIndex = 1, int pageSize = 10)
        {
            if (pageIndex <= 1)
                pageIndex = 0;
            else
                pageIndex--;

            return query.Skip(pageIndex * pageSize).Take(pageSize);
        }

        public static ObservableCollection<template> Search(string name ="", string description = "",
                                        string thumbnail = "", string image = "",
                                        
                                        int author = 0, string status = "", string url = "",
                                        DateTime? createFrom = null, DateTime? createTo = null,
                                        DateTime? updateFrom = null, DateTime? updateTo = null,
                                        string sortColumn = "id", bool isAsc = false,
                                        int pageIndex = 1, int pageSize = 10,
                                        bool isLazy = true)
        {
            using (calligraphyEntities db = new calligraphyEntities())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var query = from c in db.templates
                            where (string.IsNullOrEmpty(name) ? true : c.name.ToLower().Contains(name.ToLower()))
                            && (string.IsNullOrEmpty(description) ? true : c.name.ToLower().Contains(description.ToLower()))
                            && (string.IsNullOrEmpty(thumbnail) ? true : c.thumbnail.ToLower().Contains(thumbnail.ToLower()))
                            && (string.IsNullOrEmpty(image) ? true : c.image.ToLower().Contains(image.ToLower()))
                            && (string.IsNullOrEmpty(url) ? true : c.url.ToLower().Contains(url.ToLower()))
                            && (string.IsNullOrEmpty(status) ? true : c.status.ToLower().Contains(status.ToLower()))
                            && (author == 0 ? true : c.userid == author)
                            && (createFrom == null ? true : createFrom.Value <= c.created)
                            && (createTo == null ? true : createTo.Value >= c.created)
                            && (updateFrom == null ? true : updateFrom.Value <= c.updated)
                            && (updateTo == null ? true : updateTo.Value >= c.updated)
                            select c;

                if (!isLazy) query =  query.Include(o => o.templateControls);
                query = Sorting(query, sortColumn, isAsc);
                query = Paging(query, pageIndex, pageSize);

                if (query.Count() > 0)
                    return new ObservableCollection<template>(query.ToList());
                else
                    return new ObservableCollection<template>();
            }
        }
        #endregion
    }
}
